import { isEmpty } from "lodash-unified";

export const sum = (elements: number[]) => {
  let sum = 0;
  elements.forEach((val) => {
    sum = sum + val;
  });
  return sum;
};

export const avg = (elements: number[]) => {
  return sum(elements) / elements.length;
};

export class ArrayUtils {
  static toMap<T, K>(data: T[], keyMapper: (i: T) => K, valueMapper = (i: T) => i) {
    return data.reduce((map, ele) => {
      map.set(keyMapper(ele), valueMapper(ele));
      return map;
    }, new Map<K, T>());
  }

  static group<T, K>(data: T[], keyMapper: (i: T) => K) {
    return data.reduce((map, ele) => {
      const key = keyMapper(ele);
      let group = map.get(key);
      if (!group) {
        map.set(key, []);
        group = map.get(key);
      }
      group!.push(ele);
      return map;
    }, new Map<K, T[]>());
  }

  /**
   * 分组统计
   */
  static groupAccumulate<T, K>(data: T[], keyMapper: (i: T) => K, valueMapper: (i: T) => number) {
    return data.reduce((map, ele) => {
      const key = keyMapper(ele);
      const value = valueMapper(ele);
      map.set(key, (map.get(key) ?? 0) + value);
      return map;
    }, new Map<K, number>());
  }

  /**
   * 递归映射和展平嵌套对象的数组。
   *
   * @param data - 要展平和映射的对象的输入数组。
   * @param childrenMapper - 一个函数，它接受一个对象并以数组的形式返回其子对象，如果没有子对象，则返回 undefined。
   * @param leaf 是否只提取叶子结点
   * @param formater - 一个格式化每个对象的函数。如果未提供，则默认为 identity 函数。
   * @return  扁平化和格式化的数组。
   */
  static deepFlatmap<T, F = T>(
    data: T[],
    childrenMapper: (e: T) => T[] | undefined,
    leaf = true,
    formater = (e: T): F => e as unknown as F
  ) {
    return data.reduce((acc, node) => {
      const children = childrenMapper(node);
      const formatted = formater(node);
      if (!leaf || (leaf && isEmpty(children))) {
        acc.push(formatted);
      }
      if (!isEmpty(children)) {
        acc.push(...ArrayUtils.deepFlatmap(children!, childrenMapper, leaf, formater));
      }
      return acc;
    }, [] as F[]);
  }
}
